//#include <iostream>
//using namespace std;
//typedef long long ll;
//ll gcd(ll a, ll b)
//{
//    return b ? gcd(b, a % b) : a;
//}
//int main() {
//    ll a, b;
//    cin >> a >> b;
//    cout << (a * b) / gcd(b, a);
//    return 0;
//}


//#include <unistd.h>
//#include <unordered_set>
//class Solution {
//public:
//    /**
//     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
//     *
//     * max increasing subsequence
//     * @param arr int整型vector the array
//     * @return int整型
//     */
//     // int MLS(vector<int>& arr) {
//     //     // write code here
//     //     sort(arr.begin(),arr.end());
//     //     int ans=1;
//     //     int current=0;
//     //     for(int i=1;i<arr.size();i++)
//     //     {
//     //         if(arr[i]==(arr[i-1]+1))
//     //         {
//     //             current++;
//     //         }
//     //         else if(arr[i]==arr[i-1])
//     //         {
//     //             continue;
//     //         }
//     //         else{
//     //             ans=max(ans,current+1);
//     //             current=0;
//     //         }
//     //     }
//     //     return max(ans,current+1);
//     // }
//
//    int MLS(vector<int>& arr) {
//        unordered_set<int> s(arr.begin(), arr.end());
//        int ans = 0;
//        for (auto it : s)
//        {
//            if (s.find(it - 1) == s.end())
//            {
//                int count = 1;
//                int current = it;
//                while (s.find(current + 1) != s.end())
//                {
//                    count++;
//                    current++;
//                }
//                ans = max(count, ans);
//            }
//        }
//        return ans;
//    }
//};


// #include <iostream>
// #include <vector>
// #include <cstring>
// #include <unordered_map>
// using namespace std;
// bool vis[600][600];
// unordered_map<char, int> mp;
// int ans = 0;
// int dfs(vector<vector<char>>& grid, int n, int m, int x, int y) {
//     if (x < 0 || x >= n || y < 0 || y >= m || vis[x][y] == true) {
//         return 0;
//     }
//     vis[x][y]=true;
//     int k=0;
//     if (grid[x][y] == 'l' || grid[x][y] == 'o' || grid[x][y] == 'v' ||
//             grid[x][y] == 'e') {
//                 k=mp[grid[x][y]];
//     }
//     return k+max(dfs(grid,n,m,x+1,y),dfs(grid,n,m,x,y+1));
//     // int k=0;
//     // int k1=0;
//     // if((x+1)<n&&vis[x+1][y]==false)
//     // {
//     //     if(grid[x+1][y]=='l'||grid[x+1][y]=='o'||grid[x+1][y]=='v'||grid[x+1][y]=='e')
//     //     {
//     //         k=mp[grid[x+1][y]];
//     //     }
//     // }
//     // if((y+1)<m&&vis[x][y+1]==false)
//     // {
//     //     if(grid[x][y+1]=='l'||grid[x][y+1]=='o'||grid[x][y+1]=='v'||grid[x][y+1]=='e')
//     //     {
//     //         k1=mp[grid[x][y+1]];
//     //     }
//     // }
//     // if(k>k1)
//     // {
//     //     dfs(grid,n,m,x+1,y);
//     // }
//     // if(k1>k){
//     //     dfs(grid,n,m,x,y+1);
//     // }
//     // if(k1==k)
//     // {
//     //     vis[x+1][y]=true;
//     //     dfs(grid,n,m,x+1,y);
//     //     vis[x+1][y]=false;
//     //     vis[x][y+1]=true;
//     //     dfs(grid,n,m,x,y+1);
//     // }
// }
// int main() {
//     int n, m;
//     cin >> n >> m;
//     memset(vis, false, sizeof vis);
//     mp['l'] = 4;
//     mp['o'] = 3;
//     mp['v'] = 2;
//     mp['e'] = 1;
//     // vector<vector<char>> grid;
//     vector<vector<char>> grid(n, vector<char>(m));
//     char s;
//     for (int i = 0; i < n; i++) {
//         for (int j = 0; j < m; j++) {
//             cin >> s;
//             grid[i].push_back(s);
//         }
//     }
//     cout << dfs(grid,n,m,0,0);
//     return 0;
// }
// 64 位输出请用 printf("%lld")

// #include <iostream>
// #include <vector>
// #include <cstring>
// #include <unordered_map>
// using namespace std;

// bool vis[600][600]={false};

// unordered_map<char, int> mp;
// int ans = 0;

// int dfs(vector<vector<char>>& grid, int n, int m, int x, int y) {
//     if (x < 0 || x >= n || y < 0 || y >= m || vis[x][y]) {
//         return 0;
//     }
//     vis[x][y] = true;
//     int score = 0;
//     if (grid[x][y]=='l'||grid[x][y]=='o'||grid[x][y]=='v'||grid[x][y]=='e') {
//         score = mp[grid[x][y]];
//     }
//     int right = dfs(grid, n, m, x, y + 1);
//     int down = dfs(grid, n, m, x + 1, y);
//     int max_score = max(right, down);
//     vis[x][y] = false; // 回溯，重置vis状态
//     return score + max_score;
// }

// int main() {
//     int n, m;
//     cin >> n >> m;
//     // memset(vis, false, sizeof vis);
//     mp['l'] = 4;
//     mp['o'] = 3;
//     mp['v'] = 2;
//     mp['e'] = 1;
//     vector<vector<char>> grid(n, vector<char>(m));
//     char s;
//     for (int i = 0; i < n; i++) {
//         for (int j = 0; j < m; j++) {
//             cin >> s;
//             grid[i][j] = s;
//         }
//     }
//     cout << dfs(grid, n, m, 0, 0) << endl;
//     return 0;
// }

// #include <iostream>
// #include <vector>
// #include <cstring>
// #include <unordered_map>
// using namespace std;

// bool vis[600][600]={false};
// int dp[600][600];
// unordered_map<char, int> mp;
// int ans = 0;

// int dfs(vector<vector<char>>& grid, int n, int m, int x, int y) {
//     if (x < 0 || x >= n || y < 0 || y >= m || vis[x][y]) {
//         return 0;
//     }
//     if(dp[x][y]!=0)
//     {
//         return dp[x][y];
//     }
//     vis[x][y] = true;
//     int score = 0;
//     if (grid[x][y]=='l'||grid[x][y]=='o'||grid[x][y]=='v'||grid[x][y]=='e') {
//         score = mp[grid[x][y]];
//     }
//     int right = dfs(grid, n, m, x, y + 1);
//     int down = dfs(grid, n, m, x + 1, y);
//     int max_score = max(right, down);
//     vis[x][y]=false;
//     return dp[x][y]=score + max_score;
// }

// int main() {
//     int n, m;
//     cin >> n >> m;
//     // memset(vis, false, sizeof vis);
//     mp['l'] = 4;
//     mp['o'] = 3;
//     mp['v'] = 2;
//     mp['e'] = 1;
//     vector<vector<char>> grid(n, vector<char>(m));
//     char s;
//     for (int i = 0; i < n; i++) {
//         for (int j = 0; j < m; j++) {
//             cin >> s;
//             grid[i][j] = s;
//         }
//     }
//     cout << dfs(grid, n, m, 0, 0) << endl;
//     return 0;
// }


//  #include <iostream>
//  #include <vector>
//  #include <cstring>
//  #include <unordered_map>
//  using namespace std;

//  bool vis[600][600];
//  unordered_map<char, int> mp;
//  int dp[600][600];

//  int dfs(vector<vector<char>>& grid, int n, int m, int x, int y) {
//      if (x < 0 || x >= n || y < 0 || y >= m || vis[x][y]) {
//          return 0;
//      }
//      if (dp[x][y]!= -1) {
//          return dp[x][y];
//      }
//      vis[x][y] = true;
//      int score = 0;
//      if (grid[x][y] == 'l' || grid[x][y] == 'o' || grid[x][y] == 'v' || grid[x][y] == 'e') {
//          score = mp[grid[x][y]];
//      }
//      int right = dfs(grid, n, m, x, y + 1);
//      int down = dfs(grid, n, m, x + 1, y);
//      int max_score = max(right, down);
//      vis[x][y] = false;
//      dp[x][y] = score + max_score;
//      return dp[x][y];
//  }

//  int main() {
//      int n, m;
//      cin >> n >> m;
//      memset(vis, false, sizeof vis);
//      memset(dp, -1, sizeof dp);
//      mp['l'] = 4;
//      mp['o'] = 3;
//      mp['v'] = 2;
//      mp['e'] = 1;
//      vector<vector<char>> grid(n, vector<char>(m));
//      char s;
//      for (int i = 0; i < n; i++) {
//          for (int j = 0; j < m; j++) {
//              cin >> s;
//              grid[i][j] = s;
//          }
//      }
//      int ans = dfs(grid, n, m, 0, 0);
//      cout << ans << endl;
//      return 0;
//  }

#include <iostream>
#include <vector>
#include <cstring>
#include <unordered_map>
using namespace std;

bool vis[600][600];
unordered_map<char, int> mp;
int dp[600][600];
int maxAns = 0;

int dfs(vector<vector<char>>& grid, int n, int m, int x, int y) {
    if (x < 0 || x >= n || y < 0 || y >= m || vis[x][y]) {
        return 0;
    }
    if (dp[x][y] != -1) {
        return dp[x][y];
    }
    vis[x][y] = true;
    int score = 0;
    if (grid[x][y] == 'l' || grid[x][y] == 'o' || grid[x][y] == 'v' ||
        grid[x][y] == 'e') {
        score = mp[grid[x][y]];
    }
    int right = dfs(grid, n, m, x, y + 1);
    int down = dfs(grid, n, m, x + 1, y);
    int max_score = max(right, down);
    if (score + max_score <= maxAns) {
        vis[x][y] = false;
        dp[x][y] = score + max_score;
        return dp[x][y];
    }
    // 其他搜索方向（如果添加的话）
    // int left = dfs(grid, n, m, x, y - 1);
    // int up = dfs(grid, n, m, x - 1, y);
    // max_score = max({right, down, left, up});
    vis[x][y] = false;
    dp[x][y] = score + max_score;
    maxAns = max(maxAns, dp[x][y]);
    return dp[x][y];
}

int main() {
    int n, m;
    cin >> n >> m;
    memset(vis, false, sizeof vis);
    memset(dp, -1, sizeof dp);
    mp['l'] = 4;
    mp['o'] = 3;
    mp['v'] = 2;
    mp['e'] = 1;
    vector<vector<char>> grid(n, vector<char>(m));
    char s;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            cin >> s;
            grid[i][j] = s;
        }
    }
    int ans = dfs(grid, n, m, 0, 0);
    cout << ans << endl;
    return 0;
}
